package com.yz.sharkim.handler;

import com.yz.sharkim.entity.enums.CommonResult;
import com.yz.sharkim.entity.message.BaseMessage;
import com.yz.sharkim.entity.User;
import com.yz.sharkim.entity.message.request.Authentication;
import com.yz.sharkim.entity.message.response.CommonResponse;
import com.yz.sharkim.exception.WebSocketNotFoundException;
import com.yz.sharkim.service.IUserService;
import com.yz.sharkim.util.BeanUtil;
import com.yz.sharkim.util.ConvertUtil;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author yangzheng
 * @version 1.0
 * @date 2019/11/4
 */
@Slf4j
public class RouterWebSocket {

    private static IUserService userService;

    static void processRequest(String str, Channel channel) {
        if (userService == null) {
            userService = BeanUtil.getBean(IUserService.class);
        }
        val baseEntity = ConvertUtil.fromJson(str, BaseMessage.class);
        val apiValue = DispatchRouterHandler.get(baseEntity);
        if (apiValue == null) {
            log.error("id is {}, method not found", baseEntity.getId());
            throw new WebSocketNotFoundException(baseEntity.getId());
        }
        val method = apiValue.getMethod();
        val objects = parseParameter(method, channel, str);

        try {
            if (log.isDebugEnabled()) {
                log.debug("Controller: {}, method: {}, params: {}", apiValue.getObject().getClass().getSimpleName(),
                        apiValue.getMethod().getName(), Arrays.toString(objects));
            }
            val result = (BaseMessage) method.invoke(apiValue.getObject(), objects);
            // 配置返回流水号
            if (result != null) {
                if (objects[0] instanceof Authentication && result instanceof CommonResponse
                        && ((CommonResponse) result).getResult().equals(CommonResult.FAILED)) {
                    result.setNo(0);
                } else {
                    val no = userService.getNo(channel);
                    result.setNo(no);
                }
            }
            if (result instanceof CommonResponse && ((CommonResponse) result).getResult() == null) {
                ((CommonResponse) result).setResult(CommonResult.SUCCESS);
            }
            val resp = ConvertUtil.toJson(result);
            if (log.isDebugEnabled()) {
                log.debug("Response: {}", resp);
            }
            channel.writeAndFlush(new TextWebSocketFrame(resp));
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 参数解析
     * @param method  方法
     * @param channel 通道
     * @return 参数数组
     */
    private static Object[] parseParameter(Method method, Channel channel, String src) {
        try {
            val parameters = method.getParameters();
            val objects = new Object[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                val parameter = parameters[i];
                if (parameter.getType().equals(Channel.class)) {
                    objects[i] = channel;
                    continue;
                }
                if (parameter.getType().equals(User.class)) {
                    objects[i] = userService.getUserByChannel(channel);
                    continue;
                }
                if (parameter.getType().getSuperclass().equals(BaseMessage.class)) {
                    objects[i] = ConvertUtil.fromJson(src, parameter.getType());
                }
            }
            return objects;
        } catch (Exception e) {
            log.error("Method({}) parameters({}) parse error ! {} ", method, src, e.getMessage(), e);
            return null;
        }
    }


}
